package com.wzcl.app.service.common;

import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Maps;
import com.google.gson.JsonObject;
import com.qiniu.common.QiniuException;
import com.qiniu.http.Response;
import com.qiniu.storage.BucketManager;
import com.qiniu.storage.Region;
import com.qiniu.storage.model.BatchStatus;
import com.qiniu.util.Auth;
import com.qiniu.util.StringMap;
import com.wzcl.app.model.common.BusinessException;
import com.wzcl.app.model.dto.FileDto;
import com.wzcl.app.service.AppFileService;
import lombok.Data;
import lombok.extern.log4j.Log4j2;
import com.qiniu.storage.Configuration;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Log4j2
@Service
@Data
@PropertySource({"classpath:application-config.properties"})
public class QiNiuService {

    @Value("${qiNiu.bucket}")
    private String bucket;

    @Value("${qiNiu.domain-oss}")
    private String domain_oss;

    @Value("${qiNiu.expireSeconds}")
    private String expireSeconds;

    @Value("${qiNiu.notifyUrl}")
    private String notifyUrl;

    private static final String CALL_BACK_TYPE = "application/json";

    @Resource
    private AppFileService appFileService;

    @Resource
    private Auth auth;

    private Configuration cfg = new Configuration(Region.region0());

    private static StringMap callBackPolicy;

    public  StringMap getCallBackPolicy() {
        if(callBackPolicy == null){
            callBackPolicy = new StringMap();
            callBackPolicy.put("callbackUrl", notifyUrl);
            callBackPolicy.put("callbackBody", "{\"type\":\"$(mimeType)\",\"name\":\"$(fname)\",\"key\":\"$(key)\",\"hash\":\"$(etag)\",\"size\":$(fsize)}");
            callBackPolicy.put("callbackBodyType", CALL_BACK_TYPE);
        }
        return callBackPolicy;
    }


    public String downLoad(String fileName) throws UnsupportedEncodingException {
        String encodedFileName = URLEncoder.encode(fileName, "utf-8").replace("+", "%20");
        String publicUrl = String.format("%s/%s", domain_oss, encodedFileName);
        String finalUrl = auth.privateDownloadUrl(publicUrl, Long.valueOf(expireSeconds));
        return finalUrl;
    }

    public String uploadToken() {
        return auth.uploadToken(bucket, null,Long.valueOf(expireSeconds), getCallBackPolicy());
    }

    /**
     * 删除文件 单删
     * @param fileName  要删除的文件名
     * @return
     */
    public int deleteByFile(String fileName){
        BucketManager bucketManager = new BucketManager(auth, cfg);
        try {
            Response delete = bucketManager.delete(bucket, fileName);
            return delete.statusCode;
        } catch (QiniuException ex) {
            ex.printStackTrace();
            System.err.println(ex.code());
            System.err.println(ex.response.toString());
        }
        return -1;
    }


    /**
     *  通过数组批量删除七牛云已上传的文件
     * @param fileNames 数组形式存放的文件名
     */
    public HashMap deleteByArrayFromQiNiu(String[] fileNames) throws QiniuException{
        HashMap<String, String> maps = Maps.newHashMap();
        BucketManager bucketManager = new BucketManager(auth, cfg);
        BucketManager.BatchOperations batchOperations = new BucketManager.BatchOperations();
        batchOperations.addDeleteOp(bucket, fileNames);
        Response response = bucketManager.batch(batchOperations);
        BatchStatus[] batchStatusList = response.jsonToObject(BatchStatus[].class);
        for (int i = 0; i < fileNames.length; i++) {
            BatchStatus status = batchStatusList[i];
            String key = fileNames[i];
            System.out.print(key + "\t");
            maps.put(key, String.valueOf(status.code));
        }
        return maps;
    }


    /**
     * 通过list批量删除七牛云文件
     * @param fileNames 删除文件数组
     * @return 返回删除结果
     * @throws QiniuException
     */
    public HashMap deleteByListFromQiNiu(List<String> fileNames)throws QiniuException{
        String[] fileArr = fileNames.toArray(new String[fileNames.size()]);
        for (int i = 0; i < fileNames.size(); i++) {
            fileArr[i] = fileNames.get(i);
        }
        return deleteByArrayFromQiNiu(fileArr);
    }

    //七牛回调
    public void notify(HttpServletRequest request, HttpServletResponse response) {
        try {
            String authorization = request.getHeader("Authorization");
            BufferedReader br = new BufferedReader(new InputStreamReader(request.getInputStream()));
            String line = "";
            StringBuilder callbackBody = new StringBuilder();
            while ((line = br.readLine()) != null) {
                callbackBody.append(line);
            }
            String body = callbackBody.toString();
            boolean isCallback = auth.isValidCallback(authorization, notifyUrl, body.getBytes(), CALL_BACK_TYPE);
            if (isCallback) {
                Map<String, Object> map = convertBody(body);
                FileDto appFileDto = new FileDto();
                appFileDto.setType(String.valueOf(map.get("type")));
                appFileDto.setName(String.valueOf(map.get("name")));
                appFileDto.setHash(String.valueOf(map.get("hash")));
                appFileDto.setFileKey(String.valueOf(map.get("key")));
                appFileDto.setSrc(domain_oss+"/"+map.get("key"));
                appFileDto.setSize(Long.parseLong(String.valueOf(map.get("size"))));
                appFileService.addFile(appFileDto);
                response.setContentType("text/html");
                PrintWriter out = response.getWriter();
                JsonObject json=new JsonObject();
                json.addProperty("response", "success");
                json.addProperty("key", String.valueOf(map.get("key")));
                out.println(json.toString());
            } else {
                log.error("非七牛回调,不做处理");
            }
        } catch (Exception e) {
            log.error("七牛回调失败:{} \r\n 堆栈信息:{}",e.getMessage(),BusinessException.collectExceptionStackMsg(e));
        }
    }

    private Map<String, Object> convertBody(String body) {
        JSONObject object = JSONObject.parseObject(body);
        return object.getInnerMap();
    }
}
